package com.benjaminwan.read.free.ui.hipda

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.paging.PagedListEpoxyController
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import com.benjaminwan.read.free.R
import com.benjaminwan.read.free.base.fragment.BaseFragment
import com.benjaminwan.read.free.common.BaseUrl
import com.benjaminwan.read.free.databinding.FragmentThreadBinding
import com.benjaminwan.read.free.model.bean.DetailBean
import com.benjaminwan.read.free.model.enums.NetRetState
import com.benjaminwan.read.free.ui.net.NetViewModel
import com.benjaminwan.read.free.ui.net.NetViewModel.Companion.DefaultTid
import com.benjaminwan.read.free.utils.argsNullable
import com.benjaminwan.read.free.utils.getUrlViewIntent
import com.benjaminwan.read.free.utils.scrollToBottom
import com.benjaminwan.read.free.utils.scrollToTop
import com.benjaminwan.read.free.utils.setMarginItemDecoration
import com.benjaminwan.read.free.utils.setTitle
import com.benjaminwan.read.free.utils.showXToastError
import com.benjaminwan.read.free.utils.showXToastInfo
import com.benjaminwan.read.free.utils.showXToastSuccess
import com.benjaminwan.read.free.views.LoadingItemModel_
import com.benjaminwan.read.free.views.ThreadDetailItemViewModel_
import com.orhanobut.logger.Logger

class ThreadFragment : BaseFragment() {
    private val netVM by activityViewModel(NetViewModel::class)

    private val detailController: PagedListEpoxyController<DetailBean> by lazy { epoxyController() }

    companion object {
        const val MAX_RETRY = 3
        fun arg(tid: String): Bundle {
            val args = Bundle()
            args.putString(MvRx.KEY_ARG, tid)
            return args
        }
    }

    private var retryCount = 0
    private val tid by argsNullable<String>()
    private val threadTid: String = tid ?: DefaultTid


    private lateinit var binding: FragmentThreadBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentThreadBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        detailController.onRestoreInstanceState(savedInstanceState)
        netVM.initTid = threadTid
        netVM.pagedList.observe(subscriptionLifecycleOwner, Observer {
            detailController.submitList(it)
        })
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        detailController.onSaveInstanceState(outState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setHasOptionsMenu(true)
        initViews()
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        menu.clear()
        inflater.inflate(R.menu.menu_thread, menu)
    }

    private val threadUrl: String
        get() = "${BaseUrl}viewthread.php?tid=$threadTid"

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.menu_refresh -> {
                refresh(1)
                true
            }

            R.id.menu_scroll_top -> {
                binding.threadRv.scrollToTop()
                true
            }

            R.id.menu_scroll_bottom -> {
                binding.threadRv.scrollToBottom()
                true
            }

            R.id.menu_goto_page -> {
                showXToastInfo("此功能还未完工！")
                true
            }

            R.id.menu_open_browser -> {
                val intent = getUrlViewIntent(threadUrl)
                startActivity(intent)
                true
            }

            R.id.menu_copy_url -> {
                val clip = ClipData.newPlainText("THREAD URL FROM HiPDA", threadUrl)
                val clipboard =
                    requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                clipboard.setPrimaryClip(clip)
                showXToastSuccess("帖子地址已经复制到粘贴板")
                true
            }

            R.id.menu_paste_code -> {
                /*netVM.postReply(
                    threadTid, "<code>局势还不明朗，未来不知道会怎么样</code>".htmlEncode()
                )*/
                showXToastInfo("此功能还未完工！")
                true
            }

            else -> super.onOptionsItemSelected(item)
        }
    }

    private fun initViews() {
        binding.threadRv.setHasFixedSize(true)
        binding.threadRv.setMarginItemDecoration(4, 2, 4, 2)
        binding.threadRv.setController(detailController)
        binding.threadRefresh.setOnRefreshListener {
            refresh(1)
        }
    }

    private fun refresh(page: Int) {
        if (netVM.pagedList.hasObservers()) {
            netVM.pagedList.removeObservers(subscriptionLifecycleOwner)
        }
        netVM.refresh(detailController, threadTid, page)
        netVM.pagedList.observe(subscriptionLifecycleOwner, Observer {
            detailController.submitList(it)
        })
    }

    private fun showLoading() {
        binding.threadRefresh.isRefreshing = true
    }

    private fun hideLoading() {
        binding.threadRefresh.isRefreshing = false
    }

    override fun invalidate() = withState(netVM) { net ->
        val title = getString(R.string.page_hi_pda)
        val page = net.threadDetail?.page ?: 0
        val lastPage = net.threadDetail?.lastPage ?: 0
        if (title.isNotEmpty()) {
            setTitle("$title(已加载$page/共${lastPage}页)")
        }
        when (net.threadRequest) {
            is Success -> {
                hideLoading()
                val result = net.threadRequest()
                netVM.resetThreadRequest()
                netVM.setThreadDetail(result?.detail)
            }

            is Fail -> {
                hideLoading()
                netVM.setThreadDetail(null)
                val ret = net.threadRequest
                netVM.resetThreadRequest()
                ret.error.message?.let { showXToastError(it) }
                val result = ret()
                if (result != null && result.state == NetRetState.RE_LOGIN) {
                    if (retryCount < MAX_RETRY) {
                        retryCount++
                        showXToastInfo("登陆信息失效，正在自动重新登陆!")
                        netVM.login()
                    } else {
                        showXToastError("登陆信息失效，重新登陆多次失败，请手动登陆！")
                        findNavController().navigate(R.id.loginFragment)
                    }
                }
            }

            is Loading -> showLoading()
            else -> {
            }
        }
        when (net.postRequest) {
            is Success -> {
                hideLoading()
                val result = net.postRequest()
                Logger.i("$result")
            }

            is Fail -> {
                hideLoading()
                val ret = net.postRequest
                ret.error.message?.let { showXToastError(it) }
            }

            is Loading -> showLoading()
            else -> {
            }
        }
        Unit
    }

    private fun epoxyController() = object : PagedListEpoxyController<DetailBean>() {
        override fun buildItemModel(currentPosition: Int, item: DetailBean?): EpoxyModel<*> {
            return if (item == null) {
                LoadingItemModel_()
                    .id(-currentPosition)
            } else {
                ThreadDetailItemViewModel_()
                    .id("thread_detail_${currentPosition}_${item.hashCode()}")
                    .author(item.author)
                    .time(item.timePost)
                    .floor(item.floor.toString())
                    .postStatus(item.postStatus)
                    .contents(item.contents)
            }
        }
    }

    /*private fun epoxyController() = simpleController(netVM) { net ->
        val detailList = net.threadDetail?.all ?: emptyList()
        detailList.forEachIndexed { index, detail ->
            threadDetailItemView {
                id("thread_detail_${index}_${detail.hashCode()}")
                author(detail.author)
                time(detail.timePost)
                floor(detail.floor.toString())
                postStatus(detail.postStatus)
                contents(detail.contents)
            }
        }
    }*/

}